#!/usr/bin/env python3
# Licensing : see licensing directory

import misc
import re

def phase4 (filestree):
    """We now have each file tokenized. It's time to identify all tokens and
    create a new tree that would be syntaxically checked"""
    print ("\nPhase #4: tokenizing, Step #2")
    
    # Generates a simplest tree
    origtree = genorigtree(filestree)
    
    # Then construct a tagged from it.
    taggedtree = gentaggedtree(origtree)
    
    return misc.fend(origtree, taggedtree)

# This creates the base structure for origtree, then loops in filestree to
# extract only interesting nodes    
def genorigtree(filestree):
    """ We will store that in a tree named origtree, that will contain only 
    (under the appropriate 'Sub', 'Package' or 'Program') the file name as 
    coded, and the list of lists of tokens generated in phase3 (it sounds weird,
    but if you look at the output screen, you see it's very simple by the
    way)"""
    print ("\tPass #1: Generating a purified files tree")
    
    origtree = {'Sub':{},
        'Package':{},
        'Program':{}}
    for key in filestree['Sub']:
        origtree['Sub'][key]=filestree['Sub'][key][2]
    for key in filestree['Package']:
        origtree['Package'][key]=filestree['Package'][key][1]
    for key in filestree['Program']:
        origtree['Program'][key]=filestree['Program'][key][1]

    # Print the new origtree for debug purpose
    for key in origtree:
        print ("\t"+key+":")
        for name in origtree[key]:
            print ("\t\t"+name+":")
            for li in origtree[key][name]:
                print ("\t\t\t"+str(li))
                
    print ("\tNew files tree successfully generated")
    return origtree
    
def gentaggedtree(origtree):
    """ We will now for all tokens classify it """
    print("\tPass #2: Generating tagged tree")
    print("\t\tGenerating the cradle")

    # Creating the cradle
    taggedtree = {}
    for k in origtree:
        taggedtree[k] = {}
        for kk in origtree[k]:
            taggedtree[k][kk] = [] # It will be a list of dictionnaries
    print ("\t\t\t"+str(taggedtree))

    print ("\t\tCradle successfully generated")
    
    print ("\t\tParsing original tree")
 
    parse (origtree, taggedtree, teststring)
    #parse (origtree, taggedtree, isoperator)
     
    printree(taggedtree)

    print ("\t\tOriginal tree parsing done")    
    print ("\tTagged tree successfully generated")
    
    return taggedtree

def parse(origtree, taggedtree, func):
    """We parse the whole tree, applying testing func on all tokens """
    for k in origtree:
        for kk in origtree[k]:
            # We are on a file, as we parse file by file
            lis = []
            c = 0
            sl = []
            for line in origtree[k][kk]:
                # This list will contain one dictionnary of id: token by line
                li = []
                # Parse all tokens
                for token in line:
                    key = func(token, c, sl)
                    li.append((key, token))  # If token is a keyword, add
                                             # it to the tree
                    
                c += 1  # We count the lines, in order to be able to perform
                        # actions on other lines than the current
            
            # We add the file list to taggedtree
                lis.append(li)
            taggedtree[k][kk] += lis

def printree(taggedtree):
    """Prints the tree in a readable way"""  
    for k in taggedtree:
        print ("\t\t\t"+k)
        for kk in taggedtree[k]:
            print ("\t\t\t\t"+kk)
            for kkk in taggedtree[k][kk]:
                print ("\t\t\t\t\t"+str(kkk))

def teststring(string, c, sl):
    """Tests the string to identifie it"""
    if (re.match(r'^\s', string)):  return 'IN_'+str(len(string))
    elif (string == 'Sub'):         return 'KW_SUB'
    elif (string == 'Package'):     return 'KW_PACKAGE'
    elif (string == 'Program'):     return 'KW_PROGRAM'
    elif (string == 'Use'):         return 'KW_USE'
    elif (string == 'Procedure'):   return 'KW_PROCEDURE'
    elif (string == 'Function'):    return 'KW_FUNCTION'
    elif (string == 'If'):          return 'KW_IF'
    elif (string == 'Else'):        return 'KW_ELSE'
    elif (string == 'Class'):       return 'KW_VAR'
    elif (string == 'Array'):       return 'KW_ARRAY'
    elif (string == 'Dictionnary'): return 'KW_DICTIONNARY'
    elif (string == 'List'):        return 'KW_LIST'
    elif (string == 'Test'):        return 'KW_TEST'
    elif (string == '__ASM__'):     return 'KW_ASM'
    elif (string == '__C__'):       return 'KW_C'
    elif (string == 'NIL'):         return 'KW_NIL'
    elif (string == 'Bool'):        return 'KW_BOOL'
    elif (string == 'While'):       return 'KW_WHILE'
    elif (string == 'For'):         return 'KW_FOR'
    elif (string == 'Do'):          return 'KW_DO'
    elif (string == 'In'):          return 'KW_IN'
    elif (string == 'Break'):       return 'KW_BREAK'
    elif (string == 'Die'):         return 'KW_DIE'
    elif (string == 'Continue'):    return 'KW_CONTINUE'
    elif (string == 'Switch'):      return 'KW_SWITCH'
    elif (string == 'Case'):        return 'KW_CASE'
    elif (string == 'Default'):     return 'KW_DEFAULT'
    elif (string == 'Goto'):        return 'KW_GOTO'
    elif (string == '.'):           return 'OP_CONCATENATE'
    elif (string == ':'):           return 'OP_PASS'
    elif (string == '::'):          return 'OP_REFERENCE'
    elif (string == '=>'):          return 'OP_OUTPUT'
    elif (string == '<='):          return 'OP_INPUT'
    elif (string == '{'):           return 'OP_BLOCBEGIN'
    elif (string == '}'):           return 'OP_BLOCEND'
    elif (string == '<'):           return 'OP_INFERIOR'
    elif (string == '=<'):          return 'OP_INFEQUAL'
    elif (string == '>'):           return 'OP_SUPERIOR'
    elif (string == '>='):          return 'OP_SUPEQUAL'
    elif (string == '='):           return 'OP_EQUAL'
    elif (string == '!='):          return 'OP_NOTEQUAL'
    elif (string == '||'):          return 'OP_OR'
    elif (string == '^'):           return 'OP_XOR'
    elif (string == '*'):           return 'OP_MULTIPLY'
    elif (string == '+'):           return 'OP_PLUS'
    elif (string == '-'):           return 'OP_MINUS'
    elif (string == '/'):           return 'OP_DIVIDE'
    elif (string == '%'):           return 'OP_MODULUS'
    elif (string == '('):           return 'OP_OPENPARENTHESIS'
    elif (string == ')'):           return 'OP_CLOSEPARENTHESIS'
    elif (string == '**'):          return 'OP_EXPONENT'
    elif (string == '%/'):          return 'OP_FLOORDIVISION'
    elif (string == '<=+'):         return 'OP_AUTOADD'
    elif (string == '<=-'):         return 'OP_AUTOSUBSTRACT'
    elif (string == '<=*'):         return 'OP_AUTOMULTIPLY'
    elif (string == '<=/'):         return 'OP_AUTODIVIDE'
    elif (string == '<=%'):         return 'OP_AUTOMODULUS'
    elif (string == '<=**'):        return 'OP_AUTOEXPONENT'
    elif (string == '<=%/'):        return 'OP_AUTOFLOORDIVISION'
    elif (string == 'and'):         return 'OP_AND'
    elif (string == 'or'):          return 'OP_OR'
    elif (re.match (r'`.*`', string)):
        return 'CO_DOC'
    elif (re.match (r'`.*$', string)):
        sl.append (c)
        return 'CO_DOC'
    elif (not re.match(r'.*`$', string) and (c - 1 in sl)):
        sl.append (c)
        return 'CO_DOC'
    elif (re.match (r'.*`$', string) and (c - 1 in sl)):
        return 'CO_DOC'
    elif (re.match(r'§|@|&|<>|><|\/|\|µ|_|__\w*__|\^', string)):
        return 'DESIGNATOR'
    else:                           return 'VALUE'
    
